/**
 * UniApp HTTP请求封装
 * 功能：
 * 1. 请求/响应拦截器
 * 2. 请求取消
 * 3. 请求超时处理
 * 4. 统一错误处理
 * 5. 请求队列管理
 */

import { getToken, removeToken } from "./auth";
import env from "./env";

// 请求队列，用于管理请求
const pendingRequests = new Map();

// 生成请求的唯一标识
const generateRequestKey = (config) => {
  const { url, method, data } = config;
  return [url, method, JSON.stringify(data)].join("&");
};

// 请求拦截器
const requestInterceptors = [];

// 响应拦截器
const responseInterceptors = [];

// 添加请求拦截器
const addRequestInterceptor = (onFulfilled, onRejected) => {
  requestInterceptors.push({
    onFulfilled,
    onRejected: onRejected || ((error) => Promise.reject(error)),
  });
};

// 添加响应拦截器
const addResponseInterceptor = (onFulfilled, onRejected) => {
  responseInterceptors.push({
    onFulfilled,
    onRejected: onRejected || ((error) => Promise.reject(error)),
  });
};

// 取消请求
const cancelRequest = (requestKey) => {
  if (pendingRequests.has(requestKey)) {
    const taskInstance = pendingRequests.get(requestKey);
    taskInstance.abort(); // 取消请求
    pendingRequests.delete(requestKey);
  }
};

// 取消所有请求
const cancelAllRequests = () => {
  pendingRequests.forEach((taskInstance) => {
    taskInstance.abort();
  });
  pendingRequests.clear();
};

// 创建请求实例
const createRequest = (defaultConfig = {}) => {
  // 默认配置
  const defaults = {
    baseURL: env.baseUrl,
    timeout: 30000, // 默认超时时间：30秒
    header: {
      "content-type": "application/json",
    },
    ...defaultConfig,
  };

  // 请求方法
  const http = (config) => {
    // 合并配置
    const options = { ...defaults, ...config };

    // 构建完整URL
    options.url = `${options.baseURL}${options.url}`;

    // 添加token到请求头
    if (getToken()) {
      options.header = {
        ...options.header,
        Authorization: "Bearer " + getToken(),
      };
    }

    // 生成请求Key
    const requestKey = generateRequestKey(options);

    // 如果已存在相同请求，则取消之前的请求
    if (options.cancelDuplicated !== false && pendingRequests.has(requestKey)) {
      cancelRequest(requestKey);
    }

    // 执行请求拦截器
    let promise = Promise.resolve(options);

    requestInterceptors.forEach((interceptor) => {
      promise = promise.then(interceptor.onFulfilled, interceptor.onRejected);
    });

    return promise.then((config) => {
      return new Promise((resolve, reject) => {
        const requestTask = uni.request({
          ...config,
          success: (response) => {
            // 请求完成后从队列中移除
            pendingRequests.delete(requestKey);

            // 处理响应数据
            let res = response;

            // 执行响应拦截器
            let promise = Promise.resolve(res);
            responseInterceptors.forEach((interceptor) => {
              promise = promise.then(
                interceptor.onFulfilled,
                interceptor.onRejected
              );
            });

            promise.then(
              (response) => resolve(response),
              (error) => reject(error)
            );
          },
          fail: (error) => {
            // 请求完成后从队列中移除
            pendingRequests.delete(requestKey);
            reject(error);
          },
          complete: () => {
            // 可以在这里添加通用的完成处理逻辑
          },
        });

        // 将请求任务添加到队列
        if (options.cancelDuplicated !== false) {
          pendingRequests.set(requestKey, requestTask);
        }

        // 处理超时
        if (options.timeout) {
          setTimeout(() => {
            if (pendingRequests.has(requestKey)) {
              requestTask.abort();
              pendingRequests.delete(requestKey);
              reject(new Error("请求超时"));
            }
          }, options.timeout);
        }
      });
    });
  };

  // 便捷方法
  [
    "get",
    "post",
    "put",
    "delete",
    "head",
    "options",
    "trace",
    "connect",
  ].forEach((method) => {
    http[method] = (url, data, options = {}) => {
      return http({
        url,
        data,
        method: method.toUpperCase(),
        ...options,
      });
    };
  });

  // 上传文件方法
  http.upload = (
    url,
    { filePath, name = "file", formData = {}, header = {}, ...options } = {}
  ) => {
    const requestKey = `upload_${url}_${filePath}`;
    return new Promise((resolve, reject) => {
      const uploadTask = uni.uploadFile({
        url: `${defaults.baseURL}${url}`,
        filePath,
        name,
        formData,
        header: {
          ...header,
          ...(getToken() ? { Authorization: `Bearer ${getToken()}` } : {}),
        },
        success: (res) => {
          pendingRequests.delete(requestKey);
          // 尝试解析JSON响应
          try {
            if (typeof res.data === "string") {
              res.data = JSON.parse(res.data);
            }
          } catch (e) {
            // 解析失败，保持原样
          }
          resolve(res);
        },
        fail: (err) => {
          pendingRequests.delete(requestKey);
          reject(err);
        },
        ...options,
      });
      pendingRequests.set(requestKey, uploadTask);
    });
  };

  // 下载文件方法
  http.download = (url, options = {}) => {
    const requestKey = `download_${url}`;

    return new Promise((resolve, reject) => {
      const downloadTask = uni.downloadFile({
        url: `${defaults.baseURL}${url}`,
        header: {
          ...defaults.header,
          ...(options.header || {}),
          ...(getToken() ? { Authorization: getToken() } : {}),
        },
        success: (res) => {
          pendingRequests.delete(requestKey);
          resolve(res);
        },
        fail: (err) => {
          pendingRequests.delete(requestKey);
          reject(err);
        },
        ...options,
      });

      pendingRequests.set(requestKey, downloadTask);
    });
  };

  return http;
};

// 创建默认请求实例
const http = createRequest();

// 添加默认响应拦截器
addResponseInterceptor(
  (response) => {
    const { data } = response;

    // 如果没有返回状态码，则默认成功
    if (!data.code) {
      return data;
    }

    // 状态码判断
    if (data.code === 0) {
      return data.data;
    } else {
      // 统一错误提示
      uni.showToast({
        icon: "none",
        duration: 3000,
        title: data.desc || "请求失败",
      });

      // 处理特定错误码
      if (data.code === 401 || data.code === 403) {
        // 清除token
        removeToken();

        // 跳转到登录页
        uni.reLaunch({
          url: "/pages/login/login",
        });
      }

      return Promise.reject(data);
    }
  },
  (error) => {
    // 统一错误处理
    let message = "服务器错误，请稍后再试";

    if (error.errMsg) {
      if (error.errMsg.includes("timeout")) {
        message = "请求超时，请检查网络";
      } else if (error.errMsg.includes("abort")) {
        message = "请求已取消";
      } else if (error.errMsg.includes("fail")) {
        message = "网络连接失败，请检查网络";
      }
    }

    uni.showToast({
      icon: "none",
      duration: 3000,
      title: message,
    });

    return Promise.reject(error);
  }
);

// 导出
export {
  http as default,
  createRequest,
  addRequestInterceptor,
  addResponseInterceptor,
  cancelRequest,
  cancelAllRequests,
};
